from dataclasses import dataclass, field
import os
from pprint import pprint
from typing import Optional
import json
import uiautomator2 as u2

import xmltodict


@dataclass
class Point:
    x: int = field(default=0)
    y: int = field(default=0)


@dataclass
class Node:
    bounds: tuple[tuple[int, int], tuple[int, int]] = field(default=((0, 0), (0, 0)))
    center_point: Point = field(default_factory=Point)
    check_able: bool = field(default=False)
    checked: bool = field(default=False)
    class_name: str = field(default='')
    clickable: bool = field(default=False)
    content_desc: str = field(default='')
    enabled: bool = field(default=False)
    focusable: bool = field(default=False)
    focused: bool = field(default=False)
    index: int = field(default=0)
    long_clickable: bool = field(default=False)
    package: str = field(default='')
    password: bool = field(default=False)
    resource_id: str = field(default='')
    scrollable: bool = field(default=False)
    selected: bool = field(default=False)
    text: str = field(default='')
    # nodes: list['Node'] = field(default_factory=list,init=False)


def get_elements_tree() -> Optional[dict]:
    os.system('adb shell uiautomator dump')
    xml = os.popen('adb shell cat /sdcard/window_dump.xml').read()
    if xml is None or xml == '':
        return
    d = json.loads(json.dumps(xmltodict.parse(xml)))['hierarchy']['node']
    return d


def get_elements(trees: dict) -> list[Node]:
    clickable_elements: list[Node] = []
    if trees.get('@clickable') == 'true':
        n = Node()
        # clickable: bool = field(default=False)
        n.clickable = True
        bounds = trees.get('@bounds')
        # bounds: tuple[tuple[int, int], tuple[int, int]] = field(default=((0, 0), (0, 0)))
        if bounds != '':
            bounds = bounds.replace('[', ' ').replace(']', ' ').replace(',', ' ')
            bounds = bounds.split()
            bounds = ((int(bounds[0]), int(bounds[1])), (int(bounds[2]), int(bounds[3])))
            n.bounds = bounds
            n.center_point = Point(
                int(bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2),
                int(bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2))
        # check_able: bool = field(default=False)
        n.check_able = True if trees.get('@checkable') == 'true' else False
        # checked: bool = field(default=False)
        n.checked = True if trees.get('@checked') == 'true' else False
        # class_name: str = field(default='')
        n.class_name = trees.get('@class')
        # content_desc: str = field(default='')
        n.content_desc = trees.get('@content-desc')
        # enabled: bool = field(default=False)
        n.enabled = True if trees.get('@enabled') == 'true' else False
        # focusable: bool = field(default=False)
        n.focusable = True if trees.get('@focusable') == 'true' else False
        # focused: bool = field(default=False)
        n.focused = True if trees.get('@focused') == 'true' else False
        # index: int = field(default=0)
        n.index = int(trees.get('@index'))
        # long_clickable: bool = field(default=False)
        n.long_clickable = True if trees.get('@long-clickable') == 'true' else False
        # package: str = field(default='')
        n.package = trees.get('@package')
        # password: bool = field(default=False)
        n.password = True if trees.get('@password') == 'true' else False
        # resource_id: str = field(default='')
        n.resource_id = trees.get('@resource-id')
        # scrollable: bool = field(default=False)
        n.scrollable = True if trees.get('@scrollable') == 'true' else False
        # selected: bool = field(default=False)
        n.selected = True if trees.get('@selected') == 'true' else False
        # text: str = field(default='')
        n.text = trees.get('@text')
        clickable_elements.append(n)
    node = trees.get('node')
    if isinstance(node, dict):
        clickable_elements.extend(get_elements(node))
    if isinstance(node, list):
        for n in node:
            clickable_elements.extend(get_elements(n))
    return clickable_elements


finish: list[Node] = []


def iter_page(root_tree: list[Node]):
    if not root_tree:
        os.system(f'adb shell input keyevent 4')
    for ele in root_tree:
        if ele in finish:
            continue
        os.system(f'adb shell input tap {ele.center_point.x} {ele.center_point.y}')
        finish.append(ele)
        print(f'click:{ele.center_point.x},{ele.center_point.y}')
        new_tree = get_elements(get_elements_tree())
        for n in new_tree:
            for r in root_tree:
                if n.center_point == r.center_point:
                    try:
                        new_tree.remove(n)
                    except ValueError:
                        ...
        iter_page(new_tree)


if __name__ == '__main__':
    os.system('adb root && adb remount')
    tree = get_elements_tree()
    elements = get_elements(tree)
    iter_page(elements)
